Translating Win32 Documentation

The official Win32 API documentation is written for C and C++ programmers. So it's a good idea to learn how to translate the API function syntax from C code into ASM code. Back to Win95 ASM Page

Standard SDK calls

The routines you'll use most in ASM will be the core Win32 API functions also known as the SDK functions. Most of the functions have a fixed number of arguments, and these functions use the stdcall calling convention. The few that have a variable number of arguments (e.g., wsprintf) use the cdecl calling convention.
   A typical API function is shown in the following definition format:

        return-type function-name ( arg-type-1 arg-name-1, ... );

    So, for example, the definition of SetWindowText looks like

        BOOL SetWindowText ( HWND hWnd, LPCTSTR lpString );

    In all cases, the arguments will be pushed starting with the rightmost argument. So to call the above function, you push the arguments before calling like this:

        Push lpString
        Push hWnd
        Call SetWindowText

    If you know what the types HWND and LPCTSTR mean, you will be able to convert the call to something like this:

        push    offset title1        ; address of new title string
        push    dword ptr [ebp+8]    ; hwnd from wndproc arg list
        call    SetWindowText        ; BOOL result (success/fail) in EAX
        ; arguments already popped by SetWindowText
    The above illustrates the stdcall calling convention used by most of the Win32 API functions. SetWindowText pops the arguments so that you won't need to. If it had used the cdecl calling convention, you would've needed to reset ESP with an extra instruction, as in the following:
        add     esp,8      ; pop two DWORD arguments
    Because SetWindowText uses a character string, the documentation is actually referring to two functions: SetWindowTextA, which uses a string of ANSI (8-bit) characters, and SetWindowTextW, which uses a string of (wide 16-bit) Unicode characters. In a C program, the include file windows.h has macros that automatically control and redefine these documented names to their Unicode/ANSI-specific ones. Thus the typical program will use only the documented names.
    In MASM and TASM we can use a text macro to supply the default name:
        SetWindowText    equ    <SetWindowTextA>    ; use ANSI in Win95
    You can, if you like, use a more elaborate technique to select which name you want as default.

COM (and OLE2 and ActiveX) interface

There is also an object-based COM interface (sometimes known as OLE2 or ActiveX) which uses another calling convention. There is an extra hidden argument, which is the address of the interface record, and the function is called indirectly via an address table known as the vtable.
    The COM interface is usually programmed in C++. The syntax for a function call is typically

        interface_pointer -> function ( arglist )

    The arguments are pushed in the reverse order, just like SDK functions. The extra argument is the interface pointer which is pushed last. Then we use it to access the vtable and call the function. You will need to know the exact storage order of the function addresses. Assuming interface_pointer is in memory, the instructions would be something like

        ; ...
        ; insert argument stacking here
        ; ...
        mov     eax,[interface_pointer]
        push    eax          ; push interface pointer
        mov     ecx,[eax]    ; 1st dword of interface is vtable addr
        call    [ecx+8]      ; call the third function
        ; arguments already popped
String data in COM interfaces should always be in Unicode.

Size of data types

One type, TCHAR, is special. Its size depends on whether the C program defaults to ANSI (char) or Unicode (short).
    Some unsigned types are prefixed with U. Pointers are prefixed by P or LP. Handles are prefixed by H.
    Some sizes and the types that have them include:

BYTE: char (signed), BYTE (unsigned)
WORD: short (signed), WORD (unsigned), ATOM (unsigned)
QWORD: double (floating point)
DWORD: int (signed), DWORD (unsigned), handles, pointers, and hopefully everything else that's not a struct or related to the previous types

Register save conventions

The core Win32 functions will preserve the values of EBP, EBX, ESI, EDI, and DF. On entry, the direction flag, DF, is expected to be cleared for ascending mode in string ops.

Callbacks

Windows uses a few callback functions, the most familiar is the window procedure. These functions must follow the register save conventions used by the API functions. All of the callbacks use the stdcall calling convention.
    Because arguments are pushed in reverse order, the first listed argument is always immediately after the stacked EIP. If you use the standard prolog:
        push    ebp
        mov     ebp,esp
        sub     esp,4    ; example for allocating one local DWORD
then you can access the first argument as [ebp+8], the second argument as [ebp+12], and so on. The size of each argument is a multiple of four bytes (DWORD). Most arguments are integers, handles, or pointers: all of these are only one DWORD in size.
    The standard prolog must have a matching epilog:
        mov     esp,ebp
        pop     ebp
The arguments can be popped off with the return instruction:
        ret     16        ; example for four DWORD arguments